Vitest 单元测试配置
为什么选择 Vitest
单元测试针对单个基础组件或独立模块进行验证。选择 Vitest 而非 Jest 的核心理由:
- 兼容 Jest 语法 —
expect断言、快照测试等 API 完全兼容,迁移成本几乎为零 - 与 Vite 天然兼容 — 共用 Vite 配置,无需重复配置转换器、解析器和插件
- 开箱即用 — 内置 TypeScript、JSX 支持
安装与初始化
如果使用 create-vue 或类似脚手架创建项目,Vitest 已集成。若之前未选择单元测试,需手动安装:
pnpm add -D vitest
bash
在项目根目录创建 vitest.config.ts(优先级最高):
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
// 测试配置
}
})
typescript
项目中的配置方式
实际项目中推荐在 vite.config.ts 中通过 mergeConfig 合并配置:
import { defineConfig } from 'vite'
import { mergeConfig } from 'vitest/config'
export default mergeConfig(
defineConfig({
// Vite 配置
}),
defineConfig({
test: {
environment: 'jsdom', // DOM 解析器
exclude: ['cypress/**'] // 排除端到端测试目录
}
})
)
typescript
添加测试命令
在 package.json 的 scripts 中添加:
{
"scripts": {
"test:unit": "vitest",
"test:coverage": "vitest run --coverage"
}
}
json
编写第一个测试用例
在 src/components/__test__/ 目录下创建测试文件:
// card.test.ts
import { it, expect } from 'vitest'
it('card 组件测试', () => {
const result = true
expect(result).toBe(true)
})
typescript
运行测试:
pnpm test:unit
bash
Vitest 的 Watch 模式提供了交互式操作菜单:
| 快捷键 | 功能 |
|---|---|
A | 重新运行所有测试 |
R | 运行当前测试 |
F | 仅运行失败的测试 |
U | 更新快照 |
P | 按文件名过滤 |
T | 按正则表达式过滤 |
Q | 退出 |
测试覆盖率配置
安装覆盖率 Provider
Vitest 支持 v8 和 istanbul 两种覆盖率引擎。推荐使用 v8(默认值):
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import path from 'path'
export default defineConfig({
test: {
coverage: {
provider: 'v8', // 或 'istanbul'
reporter: ['text', 'json', 'html'], // 报告格式
// coverage 目录(仅 provider 为 istanbul 时可自定义)
}
}
})
typescript
早期版本使用的 `c8` provider 已被 `v8` 替代。官方在后续大版本中移除了 `c8` 支持,新项目请直接使用 `v8`。
:::
报告格式说明
| 格式 | 用途 |
|---|---|
text | 控制台输出,方便开发时查看 |
json | 供其他工具或组件消费 |
html | 生成可视化 HTML 报告,可分享给团队成员 |
覆盖率指标解读
运行 pnpm test:coverage 后,输出包含以下关键指标:
| 指标 | 说明 |
|---|---|
| % Stmts(语句覆盖率) | 已执行语句占总语句的百分比 |
| % Branch(分支覆盖率) | 已执行的条件分支(if/else、switch)占总分支的百分比 |
| % Funcs(函数覆盖率) | 已调用的函数占总函数的百分比 |
| % Lines(行覆盖率) | 已执行的代码行占总代码行的百分比 |
| Uncovered Line #s | 未覆盖的具体行号 |
例如,覆盖率为 84% 表示测试代码执行了 84 行代码中的所有行。未覆盖的行号可以直接定位到具体代码,分析哪些条件分支或 Props 未被测试到。
常见未覆盖原因
- 未设置某个 Prop(如
icon、imageType、border)— 导致对应条件分支未执行 - 未覆盖特定条件(如
imageType === 'avatar')— 导致该分支的代码行被跳过
Vitest UI 可视化测试工具
安装
pnpm add -D @vitest/ui
bash
在 package.json 中添加命令:
{
"scripts": {
"test:ui": "vitest --ui"
}
}
json
核心功能
- 可视化测试报告 — 在浏览器中查看测试执行结果、模块依赖图
- 快速定位失败用例 — 点击失败测试右上角的跳转按钮,直接定位到对应文件和行号
- 代码预览 — 在 UI 中直接查看运行代码
显示覆盖率面板
在 Vitest UI 中查看覆盖率报告需要满足两个条件:
- 在配置中设置
coverage.enabled: true - 在
reporter中包含'html'
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
enabled: true,
provider: 'v8',
reporter: ['text', 'json', 'html']
}
}
})
typescript
Vitest UI 的覆盖率面板实际上启动了一个本地 HTTP 服务器,将项目中生成的覆盖率 HTML 文件以 Web 方式展示。也可以通过 `npx vite preview --outDir coverage` 单独预览覆盖率报告。
覆盖率报告的预览方式
# 方式一:通过 Vitest UI 查看覆盖率面板
pnpm test:ui
# 方式二:直接预览 coverage 目录
npx vite preview --outDir coverage
bash
如果预览时显示的是缓存内容而非最新报告,可能是 PWA 缓存了旧的 HTML/JS 文件。解决方法:
- 打开 DevTools -> Application -> Storage -> 清除所有存储数据 -> 刷新
- 或使用无痕模式访问
超时配置
运行覆盖率时可能出现 teardown timeout 提示。可通过环境变量调整超时时间:
TEARDOWN_TIMEOUT=20000 pnpm test:coverage
bash
↑